<template>
  <view>
    <view
        v-if="showChoose"
        :class="{ 'xl-picker-box_hover': chooseLabel }"
        :style="{ padding: $xl.parseUnit(choosePadding, 'rpx') }"
        class="xl-picker-box"
        @click="openPicker"
    >
      <view :style="{ fontSize: $xl.parseUnit(choosefontSize, 'rpx') }" class="label">
        {{ chooseLabel ? chooseLabel : placeholder }}
      </view>
      <xl-icon color="#b1b1b1" name="xl-right" size="14"></xl-icon>
    </view>
    <xl-popup
        v-model="isVisible"
        :border-radius="centerPopup ? 12 : 0"
        :direction="centerPopup ? 'center' : 'bottom'"
        :modal-close="modalClose"
        :padding="centerPopup ? '0 20rpx' : 0"
    >
      <view class="xl-picker-popup" @click.stop="">
        <view v-if="!centerPopup" class="xl-picker-tool">
          <view :style="{ color: cancelColor }" class="btn" @click.stop="cancel">{{ cancelText || '取消' }}</view>
          <view v-if="title" class="xl-picker-tool-title">{{ title }}</view>
          <view :style="{ color: confirmColor }" class="btn" @click.stop="confirm">{{ confirmText || '确定' }}</view>
        </view>
        <view v-else-if="title" class="xl-picker-popup-title">{{ title }}</view>
        <picker-view
            :immediate-change="true"
            :indicator-style="`height: ${$xl.calcUnit(itemHeight)};`"
            :value="pickerIndexs"
            class="xl-picker"
            @change="pickerColumnchange"
        >
          <picker-view-column
              v-for="(items, index) in pickers"
              :key="index"
              class="xl-picker-column"
              @touchstart="columnClick(index)"
          >
            <view
                v-for="(item, idx) in items"
                :key="item.label"
                :class="pickerIndexs[index] === idx && 'active'"
                :style="{
                lineHeight: $xl.calcUnit(itemHeight),
                fontSize: $xl.calcUnit(itemFontSize),
              }"
                class="xl-picker-column-item"
            >{{ item.label }}
            </view>
          </picker-view-column>
        </picker-view>
        <view v-if="centerPopup" class="xl-picker-tool bottom">
          <view :style="{ color: cancelColor }" class="btn" @click.stop="cancel">{{ cancelText || '取消' }}</view>
          <view :style="{ color: confirmColor }" class="btn" @click.stop="confirm">{{ confirmText || '确定' }}</view>
        </view>
      </view>
    </xl-popup>
  </view>
</template>

<script setup>
import {computed, ref, watch} from 'vue'
import propsData from './props.js'

const props = defineProps({...propsData})

// 组件触发方法
const emits = defineEmits(['change', 'clickMask', 'update:modelValue'])

// 提供给父组件调用
defineExpose({
  openPicker,
  cancel
})

const width = computed(() => props.centerPopup ? '630rpx' : '750rpx')
const pickerHeight = computed(() => props.visibleItemCount * parseInt(props.itemHeight) + 'px')
const titleHeight = computed(() => props.centerPopup && props.title ? 60 : 0)

// 是否可见，父组件中来触发是否打开关闭弹窗
const showPicker = ref(false)
const isVisible = computed({
  get() {
    return showPicker.value || props.modelValue
  },
  set(value) {
    showPicker.value = value
    emits('update:modelValue', value)
  }
})

function openPicker() {
  isVisible.value = true
}

function cancel() {
  isVisible.value = false
}

// 当前选中label
const chooseLabel = ref('')
// 每列的数据
const pickers = ref([])
// 每列选择的索引
const pickerIndexs = ref([])
// 数据层级
const level = ref(0)

// 传入数据变化触发
watch(() => props.options, newVal => {
  // 获取传递的数据深度，并处理数据
  let {data, depth} = calculateDepthAndFillData(JSON.parse(JSON.stringify(newVal)))
  let allData = data
  pickers.value = []
  pickerIndexs.value = []
  level.value = depth
  let checkLabel = []
  // 当前选择的数据label
  for (let i = 0; i < level.value; i++) {
    if (!props.cascader) {
      data = allData[i]
    }
    let idx = 0
    if (props.defaultValue.length && props.defaultValue[i]) {
      idx = Math.max(data.findIndex(v => v.value === props.defaultValue[i]), 0)
    }
    checkLabel.push(data[idx].label)
    pickers.value[i] = data
    pickerIndexs.value[i] = idx
    if (props.cascader) {
      data = data[idx].children
    }
  }
  chooseLabel.value = props.defaultValue.length ? props.showLastLabel ? checkLabel[checkLabel.length - 1] : checkLabel.join(' ') : ''
}, {immediate: true, deep: true})

// 默认值变化触发
watch(() => props.defaultValue, newVal => {
  let data = pickers.value[0]
  let checkLabel = []
  let idxs = []
  // 当前选择的数据label
  for (let i = 0; i < level.value; i++) {
    let idx = newVal[i] ? Math.max(data.findIndex(v => v.value === props.defaultValue[i]), 0) : 0
    checkLabel.push(data[idx].label)
    idxs[i] = idx
    data = props.cascader ? data[idx].children : pickers.value[i + 1]
    if (props.cascader && i !== level.value - 1) {
      pickers.value[i + 1] = data
    }
  }
  pickerIndexs.value = idxs
  chooseLabel.value = newVal.length ? props.showLastLabel ? checkLabel[checkLabel.length - 1] : checkLabel.join(' ') : ''
})

/**
 * 计算数据的层级和包装数据
 * @param {Object} data
 */
function calculateDepthAndFillData(data) {
  if (!data || !data.length) {
    return {data: [], depth: 0}
  }
  let maxDepth = 0

  // 递归遍历数据并计算最大深度
  function traverse(node, currentDepth) {
    maxDepth = Math.max(maxDepth, currentDepth)
    node.children?.forEach(child => traverse(child, currentDepth + 1))
  }

  // 计算出深度
  if (props.cascader) {
    data.forEach(node => traverse(node, 1))
  } else {
    maxDepth = data.length
  }

  // 处理数据并填充children
  function processData(nodes, currentDepth) {
    return nodes.map((node, index) => {
      let children = node[props.childrenName]
      if (currentDepth < maxDepth) {
        // 填充children，确保深度小于最大深度时补足当前节点
        if (!children || children.length === 0) {
          children = [{...node, [props.childrenName]: undefined}]
        }
      }

      if (children && children.length > 0) {
        // 递归处理子节点
        children = processData(children, currentDepth + 1)
      }
      let obj = transformData(node, index)
      if (currentDepth < maxDepth) {
        obj.children = children
      }
      return obj
    })
  }

  function transformData(node, index) {
    let obj = {}
    obj.label = typeof node === 'string' ? node : node[props.labelName]
    obj.value = typeof node === 'string' ? index : (node[props.valueName] || index)
    return obj
  }

  return {
    depth: maxDepth,
    data: props.cascader ? processData(data, 1) : data.map(items => items.map(transformData)),
  }
}

// 记录当前滑动的列
const curColumn = ref(0)

/**
 * 滑动列触发事件，判断当前滑动的是那一列
 */
function columnClick(index) {
  curColumn.value = index
}

/**
 * 滑动值发生变化触发
 */
function pickerColumnchange(e) {
  pickerIndexs.value[curColumn.value] = e.detail.value[curColumn.value] || 0
  // 是级联数据，切换当前右边列数据
  if (props.cascader && curColumn.value !== level.value - 1) {
    let options = pickers.value[curColumn.value][pickerIndexs.value[curColumn.value]].children
    for (let i = curColumn.value + 1; i < level.value; i++) {
      pickers.value[i] = options
      options = options[0].children
      pickerIndexs.value[i] = 0
    }
  }
}

/**
 * 点击确定按钮触发
 */
function confirm() {
  let checkLabel = []
  let checkValue = []
  for (let i = 0; i < level.value; i++) {
    checkValue.push(pickers.value[i][pickerIndexs.value[i]].value)
    checkLabel.push(pickers.value[i][pickerIndexs.value[i]].label)
  }
  chooseLabel.value = checkLabel.length ? props.showLastLabel ? checkLabel[checkLabel.length - 1] : checkLabel.join(' ') : ''
  emits('change', checkValue, checkLabel, [...pickerIndexs.value])
  isVisible.value = false
}
</script>

<style lang="scss" scoped>
.xl-picker-popup {
  --popup-width: v-bind(width);
  --picker-height: v-bind(pickerHeight);
  --picker-level: v-bind(level);
  --title-height: v-bind(titleHeight);
  --active-color: v-bind(activeColor);
  width: var(--popup-width);
  height: calc(var(--picker-height) + 110rpx + var(--title-height));
  background-color: #fff;
  z-index: 999;

  &-title {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    font-size: 34rpx;
    height: 55px;
    padding-top: 5px;
  }
}

.xl-picker-tool {
  display: flex;
  justify-content: space-between;
  align-items: center;
  height: 100rpx;
  box-shadow: 0 6upx 16upx 0 hsla(0, 0%, 60%, .06);
  margin-bottom: 10rpx;

  &-title {
    font-size: 32rpx;
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  .btn {
    padding: 0 30rpx;
    font-size: 30rpx;
  }

  &.bottom {
    margin-top: 10rpx;
    margin-bottom: unset;
  }
}

.xl-picker {
  width: var(--popup-width);
  height: var(--picker-height);

  &-column {
    width: calc(var(--popup-width) / var(--picker-level));

    &-item {
      box-sizing: border-box;
      width: 100%;
      padding: 0 10rpx;
      text-align: center;
      color: #303030;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;

      &.active {
        color: var(--active-color);
        font-weight: 700;
      }
    }
  }
}

.xl-picker-box {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  color: #808080;

  &.xl-picker-box_hover {
    color: #303030;
  }

  .label {
    flex: 1;
  }

}
</style>
